home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Networking / NoCopyReceives / NoCopyReceives.c < prev    next >
Encoding:
Text File  |  2000-09-28  |  12.0 KB  |  429 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        NoCopyReceives.c
  3.  
  4.     Contains:    Minimal sample to demo no-copy receives under OT.
  5.  
  6.     Written by: Quinn "The Eskimo!"    
  7.  
  8.     Copyright:    Copyright © 1997-1999 by Apple Computer, Inc., All Rights Reserved.
  9.  
  10.                 You may incorporate this Apple sample source code into your program(s) without
  11.                 restriction. This Apple sample source code has been provided "AS IS" and the
  12.                 responsibility for its operation is yours. You are not permitted to redistribute
  13.                 this Apple sample source code as "Apple sample source code" after having made
  14.                 changes. If you're going to re-distribute the source, we require that you make
  15.                 it clear in the source that the code was descended from Apple sample source
  16.                 code, but that you've made changes.
  17.  
  18.     Change History (most recent first):
  19.                 7/22/1999    Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
  20.                 
  21.  
  22. */
  23.  
  24. /////////////////////////////////////////////////////////////////////
  25. // The OT debugging macros in <OTDebug.h> require this variable to
  26. // be set.
  27.  
  28. #ifndef qDebug
  29. #define qDebug    1
  30. #endif
  31.  
  32. /////////////////////////////////////////////////////////////////////
  33. // Pick up all the standard OT stuff.
  34. #include <Events.h>
  35. #include <Files.h>
  36. #include <OpenTransport.h>
  37. #include <OpenTptInternet.h>
  38.  
  39. /////////////////////////////////////////////////////////////////////
  40. // Pick up no-copy receive stuff, which is not in "OpenTransport.h" because
  41. // it has no mixed mode glue.
  42.  
  43. #include <OpenTptClient.h>
  44.  
  45. /////////////////////////////////////////////////////////////////////
  46. // Pick up the OTDebugBreak and OTAssert macros.
  47.  
  48. #include <OTDebug.h>
  49.  
  50. /////////////////////////////////////////////////////////////////////
  51. // Standard C prototypes.
  52.  
  53. #include <stdio.h>
  54.  
  55. /////////////////////////////////////////////////////////////////////
  56. // OTDebugStr is not defined in any OT header files, but it is
  57. // exported by the libraries, so we define the prototype here.
  58.  
  59. extern pascal void OTDebugStr(const char* str);
  60.  
  61. /////////////////////////////////////////////////////////////////////
  62.  
  63. static UInt32 gLastPrinted = 0;
  64.  
  65. static pascal void YieldingNotifier(void* contextPtr, OTEventCode code, 
  66.                                        OTResult result, void* cookie)
  67. {
  68.     #pragma unused(contextPtr)
  69.     #pragma unused(result)
  70.     #pragma unused(cookie)
  71.     
  72.     switch (code) {
  73.         case kOTSyncIdleEvent:
  74.             if ( TickCount() > gLastPrinted + 60 ) {
  75.                 printf(".");
  76.                 fflush(stdout);
  77.                 gLastPrinted = TickCount();
  78.             }
  79.             break;
  80.         default:
  81.             // do nothing
  82.             break;
  83.     }
  84. }
  85.  
  86. /////////////////////////////////////////////////////////////////////
  87.  
  88. enum {
  89.     kTransferBufferSize = 1024
  90. };
  91.  
  92. static char gTransferBuffer[kTransferBufferSize];
  93.  
  94. static OSStatus NoCopyReceiveUsingOTReadBuffer(EndpointRef ep, SInt16 destFileRefNum)
  95.     // Reads data from the endpoint using no-copy receive.  The data
  96.     // is then copied out of the OTBuffer chain using the OTReadBuffer utility
  97.     // function.  This method is useful if you need to look at a small chunk of
  98.     // data (which you can copy out using OTReadBuffer) to decide what to do with
  99.     // the rest.
  100. {
  101.     OSStatus err;
  102.     OTResult result;
  103.     OTBuffer *receivedBuffer;
  104.     OTBufferInfo bufferInfo;
  105.     OTFlags junkFlags;
  106.     UInt32 bytesRemaining;
  107.     UInt32 bytesThisTime;
  108.     SInt32 count;
  109.     
  110.     // Prepare for failure.
  111.     
  112.     err = noErr;
  113.     receivedBuffer = nil;
  114.         
  115.     // Read the data.  Use the constant kOTNetbufDataIsOTBufferStar to
  116.     // indicate that you want to do a no-copy receive.
  117.     
  118.     result = OTRcv(ep, &receivedBuffer, kOTNetbufDataIsOTBufferStar, &junkFlags);
  119.     if (result >= 0) {
  120.  
  121.         // Use the OT utility function OTBufferDataSize to calculate
  122.         // how much data OT returned.
  123.                 
  124.         bytesRemaining = OTBufferDataSize(receivedBuffer);
  125.         
  126.         // Initialise the bufferInfo data structure.
  127.  
  128.         bufferInfo.fOffset = 0;
  129.         bufferInfo.fBuffer = receivedBuffer;
  130.         
  131.         // Write that data to the file.  We do this in chunks,
  132.         // copying each chunk of data out of the OTBuffer chain
  133.         // and into our transfer buffer using the OTReadBuffer function,
  134.         // then writing each chunk of data, until there is no
  135.         // more data left in the buffer chain.  This is not a
  136.         // particularly efficient method (see below for something
  137.         // better) but it does demonstrate the use of OTReadBuffer.
  138.         
  139.         while (err == noErr && bytesRemaining > 0) {
  140.             if (bytesRemaining > kTransferBufferSize) {
  141.                 bytesThisTime = kTransferBufferSize;
  142.             } else {
  143.                 bytesThisTime = bytesRemaining;
  144.             }
  145.             (void) OTReadBuffer(&bufferInfo, gTransferBuffer, &bytesThisTime);
  146.             count = bytesThisTime;
  147.             err = FSWrite(destFileRefNum, &count, gTransferBuffer);
  148.             bytesRemaining -= bytesThisTime;
  149.         }
  150.         
  151.         err = noErr;
  152.     } else {
  153.         err = result;
  154.     }
  155.     
  156.     // Clean up.  We *must* release the OTBuffer chain back to OT
  157.     // so that it can reuse it.  Also, OTReleaseBuffer is not tolerant of
  158.     // the parameter being nil, so we check for that case first.
  159.     
  160.     if (receivedBuffer != nil) {
  161.         OTReleaseBuffer(receivedBuffer);
  162.     }
  163.     
  164.     return err;
  165. }
  166.  
  167. /////////////////////////////////////////////////////////////////////
  168.  
  169. static OSStatus NoCopyReceiveWalkingBufferChain(EndpointRef ep, SInt16 destFileRefNum)
  170.     // Reads data from the endpoint using no-copy receive.  We walk
  171.     // the resulting buffer chain, writing out chunks of data
  172.     // directly to the file from the buffers returned to us by OT.
  173. {
  174.     OSStatus err;
  175.     OTResult result;
  176.     OTBufferInfo bufferInfo;
  177.     OTBuffer *thisBuffer;
  178.     OTFlags junkFlags;
  179.     SInt32 count;
  180.     
  181.     err = noErr;
  182.  
  183.     // Initialise the bufferInfo data structure.
  184.  
  185.     bufferInfo.fOffset = 0;
  186.     bufferInfo.fBuffer = nil;
  187.     
  188.     // Read the data.  Use the constant kOTNetbufDataIsOTBufferStar to
  189.     // indicate that you want to do a no-copy receive.
  190.  
  191.     result = OTRcv(ep, &bufferInfo.fBuffer, kOTNetbufDataIsOTBufferStar, &junkFlags);
  192.     if (result >= 0) {
  193.     
  194.         // Now walk the returned buffer chain, writing out each
  195.         // chunk of data to the file.
  196.         
  197.         thisBuffer = bufferInfo.fBuffer;
  198.         while (err == noErr && thisBuffer != nil) {
  199.             
  200.             count = thisBuffer->fLen;
  201.             err = FSWrite(destFileRefNum, &count, thisBuffer->fData);
  202.             
  203.             thisBuffer = thisBuffer->fNext;
  204.         }
  205.  
  206.     } else {
  207.         err = result;
  208.     }
  209.  
  210.     // Clean up.  We *must* release the OTBuffer chain back to OT
  211.     // so that it can reuse it.  Also, OTReleaseBuffer is not tolerant of
  212.     // the parameter being nil, so we check for that case first.
  213.  
  214.     if (bufferInfo.fBuffer != nil) {
  215.         OTReleaseBuffer(bufferInfo.fBuffer);
  216.     }
  217.  
  218.     return err;
  219. }
  220.  
  221. /////////////////////////////////////////////////////////////////////
  222.  
  223. enum {
  224.     kUsingOTReadBuffer = 0,
  225.     kUseWalkingBufferChain
  226. };
  227.  
  228. static OSStatus TestNoCopyReceive(UInt8 method, SInt16 destFileRefNum)
  229.     // Test the above two no-copy receive functions by connecting
  230.     // to "www.apple.com" and downloading the root HTTP object.
  231. {
  232.     OSStatus err;
  233.     OSStatus junk;
  234.     EndpointRef ep;
  235.     DNSAddress hostDNSAddress;
  236.     TCall sndCall;
  237.     OTResult bytesSent;
  238.     char httpGetCommand[256];
  239.     
  240.     // Create a TCP endpoint.
  241.     
  242.     ep = OTOpenEndpoint(OTCreateConfiguration(kTCPName), 0, nil, &err);
  243.     
  244.     // Set up the endpoint.
  245.     
  246.     if (err == noErr) {
  247.  
  248.         // Establish the modes of operation.  This sample uses
  249.         // sync/blocking mode, with sync idle events that yield
  250.         // time using the Thread Manager.
  251.  
  252.         junk = OTSetSynchronous(ep);
  253.         OTAssert("TestNoCopyReceive: OTSetSynchronous failed", junk == noErr);
  254.         
  255.         junk = OTSetBlocking(ep);
  256.         OTAssert("TestNoCopyReceive: OTSetBlocking failed", junk == noErr);
  257.         
  258.         junk = OTInstallNotifier(ep, YieldingNotifier, nil);
  259.         OTAssert("TestNoCopyReceive: OTInstallNotifier failed", junk == noErr);
  260.         
  261.         junk = OTUseSyncIdleEvents(ep, true);
  262.         OTAssert("TestNoCopyReceive: OTUseSyncIdleEvents failed", junk == noErr);
  263.  
  264.         // Bind the endpoint.  Because we're an outgoing connection,
  265.         // we don't have to bind it to a specific address.
  266.                 
  267.         err = OTBind(ep, nil, nil);
  268.     }
  269.         
  270.     // Initialise the sndCall structure and call OTConnect.  We nil
  271.     // out most of the fields in the sndCall structure because
  272.     // we don't want any special options or connection data.
  273.     // The important field of the sndCall is the addr TNetBuf,
  274.     // which we initialise to the address "www.apple.com:80"
  275.     // (port 80 is the HTTP port).
  276.     
  277.     if (err == noErr) {
  278.         OTMemzero(&sndCall, sizeof(TCall));
  279.         sndCall.addr.buf     = (UInt8 *) &hostDNSAddress;
  280.         sndCall.addr.len     = OTInitDNSAddress(&hostDNSAddress, "www.apple.com:80");
  281.         
  282.         err = OTConnect(ep, &sndCall, nil);
  283.     }
  284.     
  285.     // Send the HTTP command to the web server.
  286.     
  287.     if (err == noErr) {
  288.         (void) sprintf(httpGetCommand, "GET / HTTP/1.0%c%c%c%c", 13, 10, 13, 10);
  289.  
  290.         bytesSent = OTSnd(ep, (void *) httpGetCommand, OTStrLength(httpGetCommand), 0);
  291.         
  292.         // OTSnd returns the number of bytes sent.  Because we're in
  293.         // synchronous mode, it won't return until it's sent all the
  294.         // bytes, or it gets an error.
  295.         
  296.         if (bytesSent > 0) {
  297.             err = noErr;
  298.         } else {
  299.             err = bytesSent;
  300.         }
  301.     }
  302.     
  303.     // Now receive the response from the server and write it to the
  304.     // destination file.
  305.     
  306.     if (err == noErr) {
  307.  
  308.         // No-copy receive does not really make sense in sync/blocking
  309.         // mode, so we switch the endpoint to sync/non-blocking before.
  310.         // proceeding.  This is reasonable because you should not be using
  311.         // no-copy receives unless you're looking for maximum speed,
  312.         // and if you're looking for maximum speed you should be using
  313.         // async/blocking mode, and doing everything in your notifier.
  314.         // In this case, I'm just trying to demonstrate it's use, so
  315.         // I make do with sync/non-blocking mode.
  316.         
  317.         junk = OTSetNonBlocking(ep);
  318.         OTAssert("TestNoCopyReceive: OTSetNonBlocking failed", junk == noErr);
  319.  
  320.         do {
  321.         
  322.             // Depending on which method we were asked to use,
  323.             // call the relevant receive function.
  324.             
  325.             switch (method) {
  326.                 case kUsingOTReadBuffer:
  327.                     err = NoCopyReceiveUsingOTReadBuffer(ep, destFileRefNum);
  328.                     break;
  329.                 case kUseWalkingBufferChain:
  330.                     err = NoCopyReceiveWalkingBufferChain(ep, destFileRefNum);
  331.                     break;
  332.                 default:
  333.                     OTDebugBreak("TestNoCopyReceive: What method?");
  334.                     err = -1;
  335.                     break;
  336.             }
  337.             
  338.             // If we get kOTNoDataErr, that means we're still waiting for data,
  339.             // so we just clear the error and continue looping.
  340.             
  341.             if (err == kOTNoDataErr) {
  342.                 YieldingNotifier(nil, kOTSyncIdleEvent, noErr, nil);
  343.                 err = noErr;
  344.             }
  345.         } while (err == noErr);
  346.         
  347.         // We will eventually leave the above loop with a kOTLookErr
  348.         // because the endpoint received either a T_ORDREL or T_DISCONNECT
  349.         // event.  Either way, the data transfer is finished, so
  350.         // we can just clear the error code and continue.
  351.         
  352.         if (err == kOTLookErr) {
  353.             err = noErr;
  354.         }
  355.     }
  356.     
  357.     // I'm not going to bother cleaning up the endpoint cleanly.
  358.     // This is the subject of another sample.  For this sample, force
  359.     // closing the endpoint is good enough.
  360.     
  361.     // Çlean up.
  362.     
  363.     if (ep != kOTInvalidEndpointRef) {
  364.         junk = OTCloseProvider(ep);
  365.         OTAssert("OTCloseProvider failed", junk == noErr);
  366.     }
  367.     return err;
  368. }
  369.  
  370. /////////////////////////////////////////////////////////////////////
  371.  
  372. void main(void)
  373.     // The main line of the sample program.  It creates
  374.     // a file in the same directory as the sample called
  375.     // "NoCopyReceive Test Output" and puts two copies
  376.     // of the root HTTP object from "www.apple.com" into
  377.     // that file.
  378. {
  379.     OSStatus err;
  380.     OSStatus junk;
  381.     FSSpec fss;
  382.     SInt16 destFileRefNum;
  383.     
  384.     printf("NoCopyReceives\n");
  385.     printf("-- Download a URL using no-copy receives\n");
  386.     printf("\n");
  387.     
  388.     err = InitOpenTransport();
  389.     
  390.     if (err == noErr) {
  391.     
  392.         // Create and open the output file.
  393.         
  394.         (void) FSMakeFSSpec(0, 0, "\pNoCopyReceive Test Output", &fss);
  395.         (void) FSpCreate(&fss, 'R*ch', 'TEXT', 0);
  396.         err = FSpOpenDF(&fss, fsRdWrPerm, &destFileRefNum);
  397.  
  398.         // Download two copies of the URL, one using the OTReadBuffer
  399.         // method, the other by the buffer walking method.
  400.  
  401.         if (err == noErr) {
  402.         
  403.             printf("Downloading using OTReadBuffer method");
  404.             err = TestNoCopyReceive(kUsingOTReadBuffer, destFileRefNum);
  405.             printf("\n\n");
  406.  
  407.             if (err == noErr) {
  408.                 printf("Downloading using 'walk the buffer chain' method");
  409.                 err = TestNoCopyReceive(kUseWalkingBufferChain, destFileRefNum);
  410.                 printf("\n\n");
  411.             }
  412.  
  413.             // Close the file.
  414.             
  415.             junk = FSClose(destFileRefNum);
  416.             OTAssert("FSClose failed", junk == noErr);
  417.         }
  418.         
  419.         CloseOpenTransport();
  420.     }
  421.     
  422.     if (err == noErr) {
  423.         printf("Success.\n");
  424.     } else {
  425.         printf("Failed with error %d.\n", err);
  426.     }
  427.     printf("Done.  Press command-Q to Quit.\n");
  428. }
  429.